package org.carpediem.conman.trash;

import org.carpediem.conman.Util;
import org.carpediem.conman.entity.ConmanPersistenceException;
import org.carpediem.conman.entity.Contact;
import org.carpediem.conman.entity.ContactNotCreatedException;
import org.carpediem.schema.conman.DocumentInfo;
import org.carpediem.schema.conman.ContactInfo;
import org.jets3t.service.S3Service;
import org.jets3t.service.S3ServiceException;
import org.jets3t.service.impl.rest.httpclient.RestS3Service;
import org.jets3t.service.model.S3Bucket;
import org.jets3t.service.model.S3Object;
import org.jets3t.service.security.AWSCredentials;

import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.WebApplicationException;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.JAXBException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Properties;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.lang.reflect.Type;
import java.lang.annotation.Annotation;

/**
 * @author Mark Petrovic
 */
public class S3 {
    private final static Logger logger = Logger.getLogger(S3.class.getName());

    public static S3Service s3Service;
    public static String documentBucketName;
    public static String noteBucketName;

    public final static String CONTACT_KEY = "contact";
    public final static String ORIGINAL_NAME = "originalName";
    private static final String PROPERTIES_FILE = "/conman.properties";

    static {
        InputStream is = S3.class.getResourceAsStream(PROPERTIES_FILE);
        if (is != null) {
            try {
                Properties awsCreds = new Properties();
                awsCreds.load(is);
                String awsAccessKey = awsCreds.getProperty("aws.key.access", "");
                String awsSecretKey = awsCreds.getProperty("aws.key.secret", "");
                documentBucketName = awsCreds.getProperty("aws.bucket.document", "");
                noteBucketName = awsCreds.getProperty("aws.bucket.note", "");
                AWSCredentials awsCredentials = new AWSCredentials(awsAccessKey, awsSecretKey);
                s3Service = new RestS3Service(awsCredentials);
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (S3ServiceException e) {
                e.printStackTrace();
            }
        } else {
            logger.severe("No S3 config file found as resource at " + PROPERTIES_FILE);
        }
    }

    public static URI saveToS3(Contact contact, DocumentInfo docInfo, byte[] docBuffer) throws ConmanPersistenceException {
        try {
            logger.info("Saving document to S3: " + docInfo.getOriginalName());
            logger.info("S3 properties: " + s3Service.getJetS3tProperties().getProperties().toString());
            S3Bucket bucket = s3Service.getOrCreateBucket(documentBucketName);
            S3Object input = docInfoToS3Object(contact, docInfo, docBuffer);
            S3Object output = S3.s3Service.putObject(bucket, input);
            logger.info("Saved document to S3: " + docInfo.getOriginalName() + " " + output);
            return s3Uri(output);
        } catch (S3ServiceException e) {
            logger.log(Level.SEVERE, "Error saving to S3", e);
            throw new ConmanPersistenceException(e);
        }
    }

    private static S3Object docInfoToS3Object(Contact contact, DocumentInfo docInfo, byte[] body) throws ContactNotCreatedException {
        byte[] digest = Util.digest(body);
        String s3FileName = Util.byteToHex(digest);

        S3Object s3Object = new S3Object(s3FileName);
        s3Object.setBucketName(S3.documentBucketName);
        s3Object.setDataInputStream(new ByteArrayInputStream(body));
        s3Object.setContentLength(body.length);
        s3Object.setContentType(docInfo.getMimetype());
        s3Object.setMd5Hash(digest);
        s3Object.addMetadata(CONTACT_KEY, contact.getEmailAddress());
        s3Object.addMetadata(ORIGINAL_NAME, docInfo.getOriginalName());

        return s3Object;
    }

    private static URI s3Uri(S3Object obj) {
        URI uri = null;
        try {
            uri = new URI("https://" + obj.getBucketName() + ".s3.amazonaws.com/" + obj.getKey());
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
        return uri;
    }

    /**
 * @author Mark Petrovic
     */
    //@Provider
    public static class Reader implements MessageBodyReader<ContactInfo> {

        public boolean isReadable(Class<?> aClass, Type type, Annotation[] annotations, MediaType mediaType) {
            System.out.println("%%%% isReadable for contactinfo");
            return aClass.isAssignableFrom(ContactInfo.class);
        }

        public ContactInfo readFrom(Class<ContactInfo> contactInfoClass, Type type, Annotation[] annotations, MediaType mediaType,
                                    MultivaluedMap<String, String> stringStringMultivaluedMap,
                                    InputStream inputStream) throws IOException, WebApplicationException {

            System.out.println("%%%% unmarshall contactinfo");

            ContactInfo cInfo = null;
            try {
                JAXBContext ctx = JAXBContext.newInstance(ContactInfo.class);
                Unmarshaller u = ctx.createUnmarshaller();
                cInfo = (ContactInfo) u.unmarshal(inputStream);
            } catch (JAXBException e) {
                e.printStackTrace();
            }
            return cInfo;
        }
    }
}
